﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Windows.Forms;
using System.ComponentModel;

namespace ProjectFinal {
	static public class FileIO {
		static private string _mediaFilename = "";		//Filename for the Books and Media
		static public string mediaFilename {					//	Accessor
			set { _mediaFilename = value; }
		}
		static private string _patronFilename = "";		//Filename for the Patrons
		static public string patronFilename {					//  Accessor
			set { _patronFilename = value; }
		}

		//Opens an XML Reader and returns a document "pointer"
		//Param:	filename to open
		//Post:		returns accessor to the XML document
		static private XmlDocument readXML(string filename) {
			XmlTextReader reader = new XmlTextReader(filename);
			reader.WhitespaceHandling = WhitespaceHandling.None;
			XmlDocument xmlDoc = new XmlDocument();
			xmlDoc.Load(reader);
			reader.Close();
			return xmlDoc;
		}//XmlDocument readXML(string)

		//Load books and movies from a file
		//Param:	Book list, Movie list
		//Pre:		mediaFilename must have a value and be a valid filename
		//Post:		both lists are populated with appropriate data from the file
		//Note:		contents of either list are cleared before reading data
		static public void loadMedia(ref BindingList<Item> lb) {
			if(_mediaFilename.Equals(""))
				throw new System.Exception("No Media filename established.\nUnable to load.");

			XmlDocument xmlDoc = readXML(_mediaFilename);
			//Ensure the root element is present
			XmlNode rootElement = xmlDoc.DocumentElement;
			if(rootElement.Name != "data")
				throw new System.Exception("Unable to find root element of name 'data' in " + _mediaFilename + ".");

			//Pass through the nodes and create the appropriate media
			foreach(XmlNode n in rootElement.ChildNodes) {
				switch(n.Name) {
					case "book":
						lb.Add(new Book(n));
						break;
					case "media":
						lb.Add(new Media(n));
						break;
					default:
						//Don't throw an exception, just display an error and continue
						MessageBox.Show("Unexpected node '" + n.Name + "' in " + _mediaFilename,
						"Media Error",
						MessageBoxButtons.OK,
						MessageBoxIcon.Error);
						break;
				}
			}
		}//void loadMedia(ref BindingList<Item>)

		//Load patrons from a file
		//Param:	Patron list
		//Pre:		patronFilename must have a value and be a valid filename
		//Post:		list is populated with appropriate data from the file
		//				returns the highest assigned ID number
		//Note:		contents of the list are cleared before reading data
		static public int loadPatrons(ref BindingList<Patron> lp) {
			if(_patronFilename.Equals(""))
				throw new System.Exception("No Patron filename established.\nUnable to load.");
			int maxID = -1;  //Obviously impossibly low value

			XmlDocument xmlDoc = readXML(_patronFilename);
			//Ensure the root element is present
			XmlNode rootElement = xmlDoc.DocumentElement;
			if(rootElement.Name != "data")
				throw new System.Exception("Unable to find root element of name 'data' in " + _patronFilename + ".");

			//Pass through the nodes and create the appropriate patron
			foreach(XmlNode n in rootElement.ChildNodes) {
				if(n.Name != "patron")  //Don't throw an exception, just display an error and continue
					MessageBox.Show("Unexpected node '" + n.Name + "' in " + _patronFilename,
							"Patron Error",
							MessageBoxButtons.OK,
							MessageBoxIcon.Error);
				else {
					lp.Add(new Patron(n));
					if(Int32.Parse(n.Attributes["id"].Value) > maxID)
						maxID = Int32.Parse(n.Attributes["id"].Value);
				}
			}
			return maxID;
		}//void loadPatrons(ref List<Patron>)

		//Write XML document to file
		//Param:	Document accessor, filename to write to
		static private void writeXML(XmlDocument xmlDoc, string filename) {
			XmlTextWriter writer = new XmlTextWriter(filename, Encoding.ASCII);
			writer.Formatting = Formatting.Indented;
			xmlDoc.Save(writer);
			writer.Close();
		}//void writeXML(XmlDocument, string)

		//Save media to a file
		//Param:	Book list, Media list
		//Pre:		mediaFilename must have a value and be a valid filename
		static public void saveMedia(BindingList<Item> li) {
			if(_mediaFilename.Equals(""))
				throw new System.Exception("No Media filename established.\nUnable to save.");
			if(File.Exists(_mediaFilename))
				File.Copy(_mediaFilename, _mediaFilename + ".bak", true);

			//Create the document to save
			XmlDocument xmlDoc = new XmlDocument();
			XmlNode rootElement = xmlDoc.CreateElement("data");
			xmlDoc.AppendChild(rootElement);
			//Write the books to the document
			foreach(Item i in li) {
				if(i is Book) {
					XmlNode node = xmlDoc.CreateElement("book");
					rootElement.AppendChild(i.writeThyself(xmlDoc, node));
				} else {
					XmlNode node = xmlDoc.CreateElement("media");
					rootElement.AppendChild(i.writeThyself(xmlDoc, node));
				}
			}
			writeXML(xmlDoc, _mediaFilename);
		}//void saveMedia(BindingList<Item>)

		//Save patrons to a file
		//Param:	Patron list
		//Pre:		patronFilename must have a value and be a valid filename
		static public void savePatrons(BindingList<Patron> lp) {
			if(_patronFilename.Equals(""))
				throw new System.Exception("No Patron filename established.\nUnable to save.");
			if(File.Exists(_patronFilename))
				File.Copy(_patronFilename, _patronFilename + ".bak", true);

			//Create the document to save
			XmlDocument xmlDoc = new XmlDocument();
			XmlNode rootElement = xmlDoc.CreateElement("data");
			xmlDoc.AppendChild(rootElement);
			//Write the patrons to the document
			foreach(Patron p in lp) {
				XmlNode node = xmlDoc.CreateElement("patron");
				rootElement.AppendChild(p.writeThyself(xmlDoc, node));
			}
			writeXML(xmlDoc, _patronFilename);
		}//void savePatrons(List<Patron>)
	}//class FileIO
}//namespace
